<?php
namespace common\services\user;

use common\models\UserModel;
use Yii;
use yii\filters\RateLimitInterface;
use yii\web\IdentityInterface;

class UserAccountService extends UserModel implements IdentityInterface, RateLimitInterface
{
    /**
     * 验证密码
     * @param string $password 用户密码
     * @return bool
     */
    public function validatePassword($password)
    {
        $pwd = sha1(md5($password . $this->password_salt));
        return Yii::$app->getSecurity()->validatePassword($pwd, $this->password_hash);
    }

    /**
     * 生成账号密码
     * @param string $password
     * @throws \yii\base\Exception
     */
    public function setPassword($password)
    {
        $passwordHashTimes = 10;//密码时间强度 数值越大 运行速度越慢
        // 随机生成20位字符 作为密码盐值
        $this->password_salt = Yii::$app->getSecurity()->generateRandomString(20);
        $pwd = sha1(md5($password . $this->password_salt)); // 密码生成算法
        // 生成密码哈希值
        $this->password_hash = Yii::$app->getSecurity()->generatePasswordHash($pwd, $passwordHashTimes);
    }

    /**
     * 生成Api登录认证token
     * Generates access token
     * @throws \yii\base\Exception
     */
    public function generateAccessToken()
    {
        // 生成唯一的token
        $this->access_token = md5($this->country_code . $this->mobile . '_' . Yii::$app->getSecurity()->generateRandomString(20));
        // token过期时间
        $this->access_token_expire = time() + 7 * 86400;
    }

    /**
     * 通过手机号码查找用户
     * @param number $mobile 手机号码
     * @param int $countryCode 国家代码
     * @return User|null
     */
    public static function findByMobile($mobile, $countryCode = 86)
    {
        return static::findOne(['mobile' => $mobile, 'country_code' => (int) $countryCode]);
    }

    /**
     * 登录成功返回登录令牌等用户信息
     * @throws \yii\base\Exception
     */
    public function loginInfo()
    {
        // 更新令牌
        $this->generateAccessToken();
        $this->save(false);//保存令牌
        return [
            'uid' => (int) $this->id,
            'nickname' => $this->nickname,
            'avatar' => $this->avatar,
            'token' => $this->access_token,
            'tokenExpire' => $this->access_token_expire
        ];
    }

    /**
     * 实现查找用户接口
     * 通过用户ID方式 查找用户表对应记录
     * @param int|string $id 用户表自增ID字段
     * @return User|null|IdentityInterface 返回用户模型对象
     */
    public static function findIdentity($id)
    {
        return static::findOne(['id' => (int) $id]);
    }

    /**
     * 实现查找用户接口
     * 通过access_token方式
     * @param string $token 令牌
     * @param null $type 令牌类型
     * @return array|null|\yii\db\ActiveRecord
     */
    public static function findIdentityByAccessToken($token, $type = null)
    {
        // 通过令牌找到用户，令牌需未过期
        return static::find()
            ->where(['and', ['access_token' => $token], ['>', 'access_token_expire', time()]])
            ->one();
    }

    /**
     * 实现获取用户ID接口
     * @return int|mixed|string
     */
    public function getId()
    {
        return $this->getPrimaryKey();
    }

    /**
     * 实现getAuthKey接口
     * @return null|string
     */
    public function getAuthKey()
    {
        return '';
    }

    /**
     * 实现验证authKey接口
     * @param string $authKey
     * @return bool|null
     */
    public function validateAuthKey($authKey)
    {
        return false;
    }

    /**
     * 实现请求速率限制接口
     * 返回允许的请求速率最大数目及限制时间
     * @param \yii\web\Request $request 当前请求
     * @param \yii\base\Action $action 执行的动作
     * @return array
     */
    public function getRateLimit($request, $action)
    {
        // 表示在 3 秒内最多 500 次的 API 调用
        return [500, 3];
    }

    /**
     * 实现请求速率限制接口
     * 返回当前允许的请求次数和最后一次速率限制检查时 相应的 UNIX 时间戳数
     * @param \yii\web\Request $request 当前请求
     * @param \yii\base\Action $action 执行的动作
     * @return array. 数组第一个元素为当前允许请求的次数, 第二个元素为相应的时间戳.
     */
    public function loadAllowance($request, $action)
    {
        // 从缓存中获取用户允许的请求次数 和 最后一次速率限制检查时间戳
        $limit = (int) Yii::$app->getCache()->get('rateLimiter_allowance_' . $this->id);
        if ($limit === false) { // 如果不存在 返回默认速率
            $limit = 500;
            Yii::$app->getCache()->set('rateLimiter_allowance_' . $this->id, $limit);
        }

        $time = Yii::$app->getCache()->get('rateLimiter_allowance_updated_at_' . $this->id);
        if ($time === false) {
            $time = time();
            Yii::$app->getCache()->set('rateLimiter_allowance_updated_at_' . $this->id, $time);
        }
        return [$limit, $time];
    }

    /**
     * 实现保存用户剩余请求数接口
     * @param \yii\web\Request $request 当前请求
     * @param \yii\base\Action $action 执行的动作
     * @param int $allowance 剩余的允许的请求次数.
     * @param int $timestamp 最后一次速率限制检查时间戳.
     */
    public function saveAllowance($request, $action, $allowance, $timestamp)
    {
        Yii::$app->getCache()->set('rateLimiter_allowance_' . $this->id, $allowance);
        Yii::$app->getCache()->set('rateLimiter_allowance_updated_at_' . $this->id, $timestamp);
    }

    /**
     * 登录成功后事件处理器
     * @param object $event 事件对象
     * @return bool
     */
    public static function afterLoginHandler($event)
    {
        //登录日志等操作
        UserLogService::afterLoginHandler($event);

        return true; // todo
    }
}